using Admin.NET.Application.Entity;
using Admin.NET.Core;
using Furion.DependencyInjection;
using Microsoft.AspNetCore.Authorization;
using SqlSugar;

namespace Admin.NET.Application.Service.Report;

/// <summary>
/// 出入库类型汇总（按入库/出库类型统计数量、占比）
/// </summary>
[ApiDescriptionSettings("Report", Name = "inOutType", Order = 906)]
[Route("api/report/inOutType")]
[AllowAnonymous]
public class InOutTypeSummaryReportService : IDynamicApiController, ITransient
{
	private readonly ISqlSugarClient _sqlSugarClient;

	public InOutTypeSummaryReportService(ISqlSugarClient sqlSugarClient)
	{
		_sqlSugarClient = sqlSugarClient;
	}

	public class GetInput
	{
		public DateTime? StartTime { get; set; }
		public DateTime? EndTime { get; set; }
	}

	public class GetDetailInput : GetInput
	{
		public int Page { get; set; } = 1;
		public int PageSize { get; set; } = 10;
	}

	public class DetailRow
	{
		public string GoodsCode { get; set; } = string.Empty;
		public string GoodsName { get; set; } = string.Empty;
		public string? Specs { get; set; }
		public string? GoodsType { get; set; }
		// 入库
		public int In_Purchase_Qty { get; set; }
		public decimal In_Purchase_Amt { get; set; }
		public int In_Product_Qty { get; set; }
		public decimal In_Product_Amt { get; set; }
		public int In_Return_Qty { get; set; }
		public decimal In_Return_Amt { get; set; }
		public int In_Profit_Qty { get; set; }
		public decimal In_Profit_Amt { get; set; }
		public int In_Other_Qty { get; set; }
		public decimal In_Other_Amt { get; set; }
		// 出库
		public int Out_Sale_Qty { get; set; }
		public decimal Out_Sale_Amt { get; set; }
		public int Out_Transfer_Qty { get; set; }
		public decimal Out_Transfer_Amt { get; set; }
		public int Out_Loss_Qty { get; set; }
		public decimal Out_Loss_Amt { get; set; }
		public int Out_Return_Qty { get; set; }
		public decimal Out_Return_Amt { get; set; }
		public int Out_Other_Qty { get; set; }
		public decimal Out_Other_Amt { get; set; }
	}

	/// <summary>
	/// 入/出库类型统计（柱状+占比数据）
	/// </summary>
	[HttpPost("summary")]
	public async Task<object> Summary([FromBody] GetInput input)
	{
		DateTime? start = input.StartTime?.Date;
		DateTime? end = input.EndTime?.Date;
		if (end != null) end = end.Value.AddDays(1).AddTicks(-1);

		var inbound = await _sqlSugarClient.Queryable<Sysinstockorder>()
			.WhereIF(start != null, x => x.InDate >= start)
			.WhereIF(end != null, x => x.InDate <= end)
			.GroupBy(x => x.InType)
			.Select(x => new { Type = SqlFunc.Coalesce(x.InType, "未分类"), Qty = SqlFunc.AggregateSum(x.InQuantity) })
			.ToListAsync();

		var outbound = await _sqlSugarClient.Queryable<Sysoutstockorder>()
			.WhereIF(start != null, x => x.OutDate >= start)
			.WhereIF(end != null, x => x.OutDate <= end)
			.GroupBy(x => x.OutType)
			.Select(x => new { Type = SqlFunc.Coalesce(x.OutType, "未分类"), Qty = SqlFunc.AggregateSum(x.OutQuantity) })
			.ToListAsync();

		int inTotal = inbound.Sum(x => x.Qty);
		int outTotal = outbound.Sum(x => x.Qty);

		var inTypes = inbound.Select(x => x.Type).ToList();
		var inQty = inbound.Select(x => x.Qty).ToList();
		var inRate = inbound.Select(x => inTotal == 0 ? 0 : Math.Round(x.Qty * 100.0 / inTotal, 2)).ToList();

		var outTypes = outbound.Select(x => x.Type).ToList();
		var outQty = outbound.Select(x => x.Qty).ToList();
		var outRate = outbound.Select(x => outTotal == 0 ? 0 : Math.Round(x.Qty * 100.0 / outTotal, 2)).ToList();

		return new { result = new { result = new
		{
			inbound = new { types = inTypes, qty = inQty, rate = inRate, total = inTotal },
			outbound = new { types = outTypes, qty = outQty, rate = outRate, total = outTotal }
		}}};
	}

	/// <summary>
	/// 出入库类型明细（表格）
	/// </summary>
	[HttpPost("detail")]
	public async Task<object> Detail([FromBody] GetDetailInput input)
	{
		DateTime? start = input.StartTime?.Date;
		DateTime? end = input.EndTime?.Date;
		if (end != null) end = end.Value.AddDays(1).AddTicks(-1);

		// 基于名称汇总，再映射到商品主数据
		var inList = await _sqlSugarClient.Queryable<Sysinstockorder>()
			.WhereIF(start != null, x => x.InDate >= start)
			.WhereIF(end != null, x => x.InDate <= end)
			.Select(x => new { x.GoodsName, x.InType, x.InQuantity, x.WarehouseAmount })
			.ToListAsync();

		var outList = await _sqlSugarClient.Queryable<Sysoutstockorder>()
			.WhereIF(start != null, x => x.OutDate >= start)
			.WhereIF(end != null, x => x.OutDate <= end)
			.Select(x => new { x.GoodsName, x.OutType, x.OutQuantity, x.OutbouAmount })
			.ToListAsync();

		// 商品主数据用于补充编码/规格/类型名称
		var goodsRaw = await _sqlSugarClient.Queryable<GoodsModel>()
			.Select(g => new { g.GoodsName, g.GoodsCode, g.GoodsSpecs, g.GoodsTypeId })
			.ToListAsync();
		var typeMap = (await _sqlSugarClient.Queryable<GoodsTypeModel>()
			.Select(t => new { t.Id, t.GoodsTypeName })
			.ToListAsync()).ToDictionary(t => t.Id, t => t.GoodsTypeName);
		var goodsDict = goodsRaw
			.GroupBy(g => g.GoodsName)
			.ToDictionary(g => g.Key, g => g.First());

		var dict = new Dictionary<string, DetailRow>();
		DetailRow getRow(string goodsName)
		{
			if (!dict.TryGetValue(goodsName, out var row))
			{
				goodsDict.TryGetValue(goodsName ?? string.Empty, out var gm);
				row = new DetailRow
				{
					GoodsName = goodsName ?? string.Empty,
					GoodsCode = gm?.GoodsCode ?? string.Empty,
					Specs = gm?.GoodsSpecs,
					GoodsType = (gm != null && gm.GoodsTypeId.HasValue && typeMap.ContainsKey(gm.GoodsTypeId.Value)) ? typeMap[gm.GoodsTypeId.Value] : string.Empty
				};
				dict[goodsName ?? string.Empty] = row;
			}
			return row;
		}

		// 归类方法（严格匹配，避免模糊匹配造成误归类）
		string norm(string? v)
		{
			return (v ?? string.Empty).Trim();
		}
		bool inSet(string t, params string[] options) => options.Contains(t);
		bool isPurchase(string? t)
		{
			var s = norm(t);
			return inSet(s, "进货入库", "采购入库");
		}
		bool isProduct(string? t)
		{
			var s = norm(t);
			return inSet(s, "生产入库");
		}
		bool isReturnIn(string? t)
		{
			var s = norm(t);
			return inSet(s, "退货入库");
		}
		bool isProfit(string? t)
		{
			var s = norm(t);
			return inSet(s, "盘盈入库");
		}
		// 出库分类
		bool isSale(string? t)
		{
			var s = norm(t);
			return inSet(s, "销售出库");
		}
		bool isTransfer(string? t)
		{
			var s = norm(t);
			return inSet(s, "调拨出库");
		}
		bool isLoss(string? t)
		{
			var s = norm(t);
			return inSet(s, "盘亏出库");
		}
		bool isReturnOut(string? t)
		{
			var s = norm(t);
			return inSet(s, "退货出库");
		}

		foreach (var r in inList)
		{
			var row = getRow(r.GoodsName ?? string.Empty);
			if (isPurchase(r.InType)) { row.In_Purchase_Qty += r.InQuantity; row.In_Purchase_Amt += r.WarehouseAmount; }
			else if (isProduct(r.InType)) { row.In_Product_Qty += r.InQuantity; row.In_Product_Amt += r.WarehouseAmount; }
			else if (isReturnIn(r.InType)) { row.In_Return_Qty += r.InQuantity; row.In_Return_Amt += r.WarehouseAmount; }
			else if (isProfit(r.InType)) { row.In_Profit_Qty += r.InQuantity; row.In_Profit_Amt += r.WarehouseAmount; }
			else { row.In_Other_Qty += r.InQuantity; row.In_Other_Amt += r.WarehouseAmount; }
		}

		foreach (var r in outList)
		{
			var row = getRow(r.GoodsName ?? string.Empty);
			if (isSale(r.OutType)) { row.Out_Sale_Qty += r.OutQuantity; row.Out_Sale_Amt += r.OutbouAmount; }
			else if (isTransfer(r.OutType)) { row.Out_Transfer_Qty += r.OutQuantity; row.Out_Transfer_Amt += r.OutbouAmount; }
			else if (isLoss(r.OutType)) { row.Out_Loss_Qty += r.OutQuantity; row.Out_Loss_Amt += r.OutbouAmount; }
			else if (isReturnOut(r.OutType)) { row.Out_Return_Qty += r.OutQuantity; row.Out_Return_Amt += r.OutbouAmount; }
			else { row.Out_Other_Qty += r.OutQuantity; row.Out_Other_Amt += r.OutbouAmount; }
		}

		var all = dict.Values.OrderBy(v => v.GoodsCode).ThenBy(v => v.GoodsName).ToList();
		var total = all.Count;
		var pageItems = all.Skip((input.Page - 1) * input.PageSize).Take(input.PageSize).ToList();

		return new { result = new { result = new { items = pageItems, total, page = input.Page, pageSize = input.PageSize } } };
	}
}


